package lu.uni.adtool.domains;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import java.util.Set;
import java.util.Vector;

import org.reflections.Reflections;

import lu.uni.adtool.domains.predefined.*;

/**
 * Creates Domains.
 * 
 * @author Piot Kordy
 */
public abstract class DomainFactory
{
  private static final String domainsPrefix 
    = "lu.uni.adtool.domains.predefined";

  /**
   * Constructs a new instance.
   */
  public DomainFactory()
  {
  }

  /**
   * Creates predefined domain from string name.
   * 
   * @param domainName domain class name
   * @return created domain.
   */
  public static Domain createFromString(String domainName)
  {
    Constructor<Domain>[] ct=null;
    try{
      final Class c = Class.forName(domainsPrefix+"."+domainName);
      ct = (Constructor<Domain>[]) c.getDeclaredConstructors();
    }
    catch(ClassNotFoundException e){
      return null;
    }
    Domain d = null;
    if (ct.length == 1) {
      try{
        d = ct[0].newInstance();
      }
      catch(InstantiationException e){
        System.err.println(e);
        return null;
      }
      catch(IllegalAccessException e){
        System.err.println(e);
        return null;
      }
      catch(InvocationTargetException e){
        System.err.println(e);
        return null;
      }
    }
    return d;
  }
  /**
   * Get domain class name as string.
   * 
   * @param d domain.
   * @return domain class name.
   */
  public static String getClassName(Domain d){
    return d.getClass().getSimpleName();
  }

  /**
   * Returns string list of predefined domains.
   * 
   * @return array of strings with domain names.
   */
  public static Vector<Domain> getPredefinedDomains()
  {
    Vector<Domain> result = new Vector<Domain>();
    Reflections reflections = new Reflections(domainsPrefix);
    Set<Class<? extends Domain>> m = reflections.getSubTypesOf(Domain.class);
    for (Class<? extends Domain> c : m) {
      Domain d = null;
      Constructor<Domain>[] ct = (Constructor<Domain>[]) c
          .getDeclaredConstructors();
      try {
        if (ct.length == 1) {
          d = ct[0].newInstance();
          result.add((Domain)d);
        }
      }
      catch (InstantiationException e) {
        System.err.println(e);
        return null;
      }
      catch (IllegalAccessException e) {
        System.err.println(e);
        return null;
      }
      catch (InvocationTargetException e) {
        System.err.println(e);
        return null;
      }
    }
    // fixing not loading classes under webstart
    if (result.size()==0){
      result.add(new BoolAndOr());
      result.add(new BoolOrAnd());
      result.add(new BoolOrAndStar());
      result.add(new ProbPlusTimes());
      result.add(new RealG0MinSumCost());
      result.add(new RealG0MinSum());
      result.add(new RealG0MinSumParallel());
      result.add(new IntMinMax());
      result.add(new IntMinSum());
      result.add(new IntMinMinMax());

    }
    return result;
  }
}

